package com.zxp.utils.configParseUtils;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.MissingNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.zxp.utils.fileUtils.FileUtils;

import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;

public class JsonAppender {

    private static final ObjectMapper objectMapper = new ObjectMapper();
    private static File jsonFile;

    public static void setJsonFile(String filePath) {
        jsonFile = new File(filePath);
    }

    /**
     * Append JSON content to the file.
     * @param jsonContent The JSON content to append.
     * @throws IOException If an I/O error occurs.
     */
    public static void appendJsonContent(String jsonContent) throws IOException {
        ObjectNode rootNode = readJsonFile();

        JsonNode newContent = objectMapper.readTree(jsonContent);
        mergeJsonNodes(rootNode, (ObjectNode) newContent);

        writeJsonFile(rootNode);
    }

    /**
     * Append a key-value pair to the file.
     * @param key The key to append.
     * @param value The value to append.
     * @throws IOException If an I/O error occurs.
     */
    public static void appendKeyValuePair(String key, String value) throws IOException {
        ObjectNode rootNode = readJsonFile();

        if (!containsKey(rootNode, key)) {
            putKeyValuePair(rootNode, key, value);
            writeJsonFile(rootNode);
        } else {
            System.err.println("Key already exists. Please choose a unique key.");
        }
    }

    /**
     * Read the JSON file and return the JSON object.
     * @return The JSON object.
     * @throws IOException If an I/O error occurs.
     */
    private static ObjectNode readJsonFile() throws IOException {
        if (!jsonFile.exists()) {
            return objectMapper.createObjectNode();
        }
        return (ObjectNode) objectMapper.readTree(jsonFile);
    }

    /**
     * Write the JSON object to the file.
     * @param rootNode The JSON object to write.
     * @throws IOException If an I/O error occurs.
     */
    private static void writeJsonFile(JsonNode rootNode) throws IOException {
        objectMapper.writeValue(jsonFile, rootNode);
    }

    /**
     * Check if the JSON object contains the specified key.
     * @param rootNode The JSON object to check.
     * @param key The key to check.
     * @return true if the JSON object contains the key, false otherwise.
     */
    private static boolean containsKey(ObjectNode rootNode, String key) {
        Iterator<Map.Entry<String, JsonNode>> fields = rootNode.fields();

        while (fields.hasNext()) {
            Map.Entry<String, JsonNode> entry = fields.next();
            String existingKey = entry.getKey();
            JsonNode existingValue = entry.getValue();

            if (existingKey.equals(key)) {
                return true;
            }

            if (existingValue.isObject()) {
                if (containsKey((ObjectNode) existingValue, key)) {
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * Merge two JSON objects.
     * @param targetNode The JSON object to merge into.
     * @param sourceNode The JSON object to merge from.
     */
    private static void mergeJsonNodes(ObjectNode targetNode, JsonNode sourceNode) {
        Iterator<Map.Entry<String, JsonNode>> fields = sourceNode.fields();

        while (fields.hasNext()) {
            Map.Entry<String, JsonNode> entry = fields.next();
            String sourceKey = entry.getKey();
            JsonNode sourceValue = entry.getValue();

            if (targetNode.has(sourceKey)) {
                JsonNode targetValue = targetNode.get(sourceKey);

                if (targetValue.isObject() && sourceValue.isObject()) {
                    // 递归合并两个 ObjectNode
                    mergeJsonNodes((ObjectNode) targetValue, (ObjectNode) sourceValue);
                } else {
                    // 直接设置非 ObjectNode 类型的值
                    targetNode.set(sourceKey, createJsonNode(sourceValue));
                }
            } else {
                // 目标节点中不存在该键，使用 JsonNodeFactory 创建新节点并添加
                targetNode.set(sourceKey, createJsonNode(sourceValue));
            }
        }
    }


    private static JsonNode createJsonNode(JsonNode sourceValue) {
        if (sourceValue.isObject()) {
            // 如果是 ObjectNode，直接返回
            return sourceValue;
        } else {
            // 如果不是 ObjectNode，使用 JsonNodeFactory 创建新节点
            return JsonNodeFactory.instance.objectNode().setAll((ObjectNode) sourceValue);
        }
    }





    /**
     * Put a key-value pair into the JSON object.
     * @param rootNode The JSON object to put the key-value pair into.
     * @param key The key to put.
     * @param value The value to put.
     */
    private static void putKeyValuePair(ObjectNode rootNode, String key, String value) {
        String[] keyParts = key.split("\\.");
        ObjectNode currentNode = rootNode;

        for (int i = 0; i < keyParts.length - 1; i++) {
            String part = keyParts[i];
            if (!currentNode.has(part)) {
                currentNode.set(part, objectMapper.createObjectNode());
            }
            currentNode = (ObjectNode) currentNode.get(part);
        }

        currentNode.put(keyParts[keyParts.length - 1], value);
    }

    public static void main(String[] args) throws IOException {
        // Example: append key-value pair
        String key = "Init_JAVA_HOME";
        String javaHome = "/path/to/java/home";
        JsonAppender.setJsonFile("path/to/your/directory/file.json");
        JsonAppender.appendKeyValuePair(key, javaHome);
    }
}
